#include "lcd.h"
#include "font.h"
#include "main.h"

// 定义帧缓冲区（根据你的LCD实际分辨率调整）
#define FRAME_WIDTH  156  // 根据你的显示区域设置
#define FRAME_HEIGHT 12
uint16_t lineFrameBuffer[FRAME_WIDTH * FRAME_HEIGHT]; // 假设为1bpp（单色）
struct gs_host_frame g_printFrame;
uint8_t g_haveFrame = 0;
uint8_t g_frameShowCnt = 0;
uint8_t g_frameType = CAN_NOACT;
uint8_t g_canStatus = CAN_DISCONNECT;

//LCD的画笔颜色和背景色	   
u16 POINT_COLOR=WHITE;	//画笔颜色
u16 BACK_COLOR=BLACK;  //背景色 
//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;

void MCU_write_TFT_Byte(u8 data, u8 cmd)
{
	HAL_StatusTypeDef ret = 0;
    if (cmd == TFT_COMMAND) {
        TFT_RS(0);
    } else if(cmd == TFT_DATA){
        TFT_RS(1);
    }
    HAL_SPI_Transmit(&hspi1, &data, 1, 10);
}

u16 Swap(u16 data)
{
	u16 temp;
	temp = (data>>8)&0XFF;
	data = data&0XFF;
	data = (data<<8)|temp;
	return data;
}

void MCU_write_TFT_Word(u16 data)
{
	HAL_StatusTypeDef ret = 0;
    TFT_RS(1);
	// data = Swap(data);
    ret = HAL_SPI_Transmit(&hspi1, (u8*)&data, 2, 10);
}

//设置LCD显示方向
//dir:0,竖屏；1,横屏
void LCD_Display_Dir(u8 dir)
{
 	if(dir==0)			//竖屏
	{
		lcddev.dir=0;	//竖屏
		lcddev.width=80;
		lcddev.height=160;

		lcddev.wramcmd=0X2C;
		lcddev.setxcmd=0X2A;
		lcddev.setycmd=0X2B;
        lcddev.xoffset = 26;
        lcddev.yoffset = 1;

	}else 				//横屏
	{	  				
		lcddev.dir=1;	//横屏
		lcddev.width=160;
		lcddev.height=80;

		lcddev.wramcmd=0X2C;
		lcddev.setxcmd=0X2A;
		lcddev.setycmd=0X2B;

        lcddev.xoffset = 1;
        lcddev.yoffset = 26;
	} 
}

void TFT_init(void)
{
	TFT_BL(0);//背光关闭
	
	TFT_RESET(1);
	HAL_Delay(5);
	TFT_RESET(0);
	HAL_Delay(5);
	TFT_RESET(1);
	HAL_Delay(20);

	MCU_write_TFT_Byte(0x01,TFT_COMMAND);
	HAL_Delay(50);
	
	MCU_write_TFT_Byte(0x11,TFT_COMMAND);//睡眠退出
	HAL_Delay(50);
//------------------------------------ST7735S Frame Rate-----------------------------------------// 
	MCU_write_TFT_Byte(0xB1, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x05, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0xB2, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x05, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0xB3, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x05, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0x05, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 
	MCU_write_TFT_Byte(0x3C, TFT_DATA); 

	//------------------------------------End ST7735S Frame Rate---------------------------------// 
	MCU_write_TFT_Byte(0xB4, TFT_COMMAND); //Dot inversion 
	MCU_write_TFT_Byte(0x03, TFT_DATA); 
	//------------------------------------ST7735S Power Sequence---------------------------------// 
	MCU_write_TFT_Byte(0xC0, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x28, TFT_DATA); 
	MCU_write_TFT_Byte(0x08, TFT_DATA); 
	MCU_write_TFT_Byte(0x04, TFT_DATA); 
	MCU_write_TFT_Byte(0xC1, TFT_COMMAND); 
	MCU_write_TFT_Byte(0XC0, TFT_DATA); 
	MCU_write_TFT_Byte(0xC2, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x0D, TFT_DATA); 
	MCU_write_TFT_Byte(0x00, TFT_DATA); 
	MCU_write_TFT_Byte(0xC3, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x8D, TFT_DATA); 
	MCU_write_TFT_Byte(0x2A, TFT_DATA); 
	MCU_write_TFT_Byte(0xC4, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x8D, TFT_DATA); 
	MCU_write_TFT_Byte(0xEE, TFT_DATA); 
	//---------------------------------End ST7735S Power Sequence-------------------------------------// 
	MCU_write_TFT_Byte(0xC5, TFT_COMMAND); //VCOM 
	MCU_write_TFT_Byte(0x18, TFT_DATA);    //1a
	MCU_write_TFT_Byte(0x36, TFT_COMMAND); //MX, MY, RGB mode 
	// MCU_write_TFT_Byte(0xC8, TFT_DATA); 
	switch (1)//显示的方向(竖屏:0,横屏:1,竖屏旋转180度:2,横屏旋转180度:3)
	{
		case	0: MCU_write_TFT_Byte(0xC8,TFT_DATA);break;//竖屏
		case	1: MCU_write_TFT_Byte(0xA0,TFT_DATA);break;//横屏,RGB为0
		case    2: MCU_write_TFT_Byte(0x08,TFT_DATA);break;//竖屏翻转180度
		default	 : MCU_write_TFT_Byte(0x60,TFT_DATA);break;//横屏翻转180度,RGB为0
	}

	//------------------------------------ST7735S Gamma Sequence---------------------------------// 
	MCU_write_TFT_Byte(0xE0, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x04, TFT_DATA); 
	MCU_write_TFT_Byte(0x22, TFT_DATA); 
	MCU_write_TFT_Byte(0x07, TFT_DATA); 
	MCU_write_TFT_Byte(0x0A, TFT_DATA); 
	MCU_write_TFT_Byte(0x2E, TFT_DATA); 
	MCU_write_TFT_Byte(0x30, TFT_DATA); 
	MCU_write_TFT_Byte(0x25, TFT_DATA); 
	MCU_write_TFT_Byte(0x2A, TFT_DATA); 
	MCU_write_TFT_Byte(0x28, TFT_DATA); 
	MCU_write_TFT_Byte(0x26, TFT_DATA); 
	MCU_write_TFT_Byte(0x2E, TFT_DATA); 
	MCU_write_TFT_Byte(0x3A, TFT_DATA); 
	MCU_write_TFT_Byte(0x00, TFT_DATA); 
	MCU_write_TFT_Byte(0x01, TFT_DATA); 
	MCU_write_TFT_Byte(0x03, TFT_DATA); 
	MCU_write_TFT_Byte(0x13, TFT_DATA); 
	MCU_write_TFT_Byte(0xE1, TFT_COMMAND); 
	MCU_write_TFT_Byte(0x04, TFT_DATA); 
	MCU_write_TFT_Byte(0x16, TFT_DATA); 
	MCU_write_TFT_Byte(0x06, TFT_DATA); 
	MCU_write_TFT_Byte(0x0D, TFT_DATA); 
	MCU_write_TFT_Byte(0x2D, TFT_DATA); 
	MCU_write_TFT_Byte(0x26, TFT_DATA); 
	MCU_write_TFT_Byte(0x23, TFT_DATA); 
	MCU_write_TFT_Byte(0x27, TFT_DATA); 
	MCU_write_TFT_Byte(0x27, TFT_DATA); 
	MCU_write_TFT_Byte(0x25, TFT_DATA); 
	MCU_write_TFT_Byte(0x2D, TFT_DATA); 
	MCU_write_TFT_Byte(0x3B, TFT_DATA); 
	MCU_write_TFT_Byte(0x00, TFT_DATA); 
	MCU_write_TFT_Byte(0x01, TFT_DATA); 
	MCU_write_TFT_Byte(0x04, TFT_DATA); 
	MCU_write_TFT_Byte(0x13, TFT_DATA); 
	//------------------------------------End ST7735S Gamma Sequence-----------------------------// 
	MCU_write_TFT_Byte(0x3A, TFT_COMMAND); //65k mode 
	MCU_write_TFT_Byte(0x05, TFT_DATA); 
	MCU_write_TFT_Byte(0x29, TFT_COMMAND); //Display on 
	//MCU_write_TFT_Byte(0x20, TFT_COMMAND); //Display Inversion Off
	MCU_write_TFT_Byte(0x21, TFT_COMMAND); //Display Inversion On

  	LCD_Display_Dir(1);
	TFT_BL(1);//背光开启
	LCD_Fill(0,0,159,79, BLACK);//清屏(屏幕为黑色)
//	while(1);
}


//设置窗口,并自动设置画点坐标到窗口左上角(sx,sy).
//sx,sy:窗口起始坐标(左上角)
//width,height:窗口宽度和高度,必须大于0!!
//窗体大小:width*height. 
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
{    
	u16 twidth = 0,theight = 0;

	sx += lcddev.xoffset;
    // width += lcddev.xoffset;

	sy += lcddev.yoffset;
    // height += lcddev.yoffset;

	twidth=sx+width - 1;
	theight=sy+height - 1;

	MCU_write_TFT_Byte(lcddev.setxcmd, TFT_COMMAND); 
	MCU_write_TFT_Byte(sx>>8, TFT_DATA); 
	MCU_write_TFT_Byte(sx&0XFF, TFT_DATA);//xstart
	MCU_write_TFT_Byte(twidth>>8, TFT_DATA); 
	MCU_write_TFT_Byte(twidth&0XFF, TFT_DATA);	//xend
  	
	MCU_write_TFT_Byte(lcddev.setycmd, TFT_COMMAND); 
	MCU_write_TFT_Byte(sy>>8, TFT_DATA); 
	MCU_write_TFT_Byte(sy&0XFF, TFT_DATA);//ystart
	MCU_write_TFT_Byte(theight>>8, TFT_DATA); 
	MCU_write_TFT_Byte(theight&0XFF, TFT_DATA);	//yend
	
	MCU_write_TFT_Byte(lcddev.wramcmd, TFT_COMMAND); 
}

extern DMA_HandleTypeDef hdma_spi1_tx;
//在指定区域内填充单个颜色
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   
//color:要填充的颜色
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{          
	u16 i,pix;
	u16 xlen=0;
	u16 ylen=0;

	xlen=ex-sx;
	ylen=ey-sy;
	LCD_Set_Window(sx,sy,xlen,ylen);
	TFT_RS(1);
	u16 data[10*160] = {0};

	for(i=0;i<10*160;i++) {
	    data[i] = color;
	}
	for(i=0;i<8;i++)
	{
		HAL_SPI_Transmit_DMA(&hspi1, (u8*)&data, 160*20);
		while(HAL_DMA_GetState(&hdma_spi1_tx) == HAL_DMA_STATE_BUSY);
    	// HAL_SPI_Transmit(&hspi1, (u8*)&data, 160*20, 1000);
	}
	return;
}
#include "config.h"
void lcd_test(void)
{
	u16 colors[] = {WHITE, BLACK, BLUE, RED};
	u16 cnt = 0;
	u16 data[20*160] = {0};

	while(1)
	{
		LCD_Fill(0,0,160,80, colors[cnt&0x01]);
//		LCD_Set_Window(0,0,160,80);
//		TFT_RS(1);
//		memset((void*)data, colors[cnt&0x01], 40*160);
//		HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)data, 40*160);
//		HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)data, 40*160);
//		HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)data, 40*160);
//		HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)data, 40*160);
		HAL_Delay(1000);
		HAL_GPIO_TogglePin(LEDRX_GPIO_Port, LEDRX_Pin);
		cnt++;
	}
}

//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
	Xpos += lcddev.xoffset;
    Ypos += lcddev.yoffset;
	MCU_write_TFT_Byte(lcddev.setxcmd, TFT_COMMAND);
	MCU_write_TFT_Byte(Xpos>>8, TFT_DATA);
	MCU_write_TFT_Byte(Xpos&0XFF, TFT_DATA);
	MCU_write_TFT_Byte(Xpos>>8, TFT_DATA);
	MCU_write_TFT_Byte(Xpos&0XFF, TFT_DATA);
  	
	MCU_write_TFT_Byte(lcddev.setycmd, TFT_COMMAND);
	MCU_write_TFT_Byte(Ypos>>8, TFT_DATA);
	MCU_write_TFT_Byte(Ypos&0XFF, TFT_DATA);
	MCU_write_TFT_Byte(Ypos>>8, TFT_DATA);
	MCU_write_TFT_Byte(Ypos&0XFF, TFT_DATA);

	MCU_write_TFT_Byte(lcddev.wramcmd, TFT_COMMAND);
} 	
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
	LCD_SetCursor(x,y);		//设置光标位置 
    MCU_write_TFT_Word(POINT_COLOR);
}
//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)
{	   
	LCD_SetCursor(x,y);		//设置光标位置
    MCU_write_TFT_Word(color);
}

//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)
{  							  
    u8 temp,t1,t;
	u16 y0=y;
	u8 csize=(size/8+((size%8)?1:0))*(size/2);		//得到字体一个字符对应点阵集所占的字节数	
 	num=num-' ';//得到偏移后的值（ASCII字库是从空格开始取模，所以-' '就是对应字符的字库）
	for(t=0;t<csize;t++)
	{
		if(size==12)temp=asc2_1206[num][t]; 	 	//调用1206字体
		else if(size==16)temp=asc2_1608[num][t];	//调用1608字体
		else if(size==24)temp=asc2_2412[num][t];	//调用2412字体
		else return;								//没有的字库
		for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);
			else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);
			temp<<=1;
			y++;
			if(y>=lcddev.height)return;		//超区域了
			if((y-y0)==size)
			{
				y=y0;
				x++;
				if(x>=lcddev.width)return;	//超区域了
				break;
			}
		}  	 
	}  	    	   	 	  
}   
//m^n函数
//返回值:m^n次方.
u32 LCD_Pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}			 
//显示数字,高位为0,则不显示
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//color:颜色 
//num:数值(0~4294967295);	 
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/LCD_Pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				LCD_ShowChar(x+(size/2)*t,y,' ',size,0);
				continue;
			}else enshow=1; 
		 	 
		}
	 	LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0); 
	}
} 
//显示数字,高位为0,还是显示
//x,y:起点坐标
//num:数值(0~999999999);	 
//len:长度(即要显示的位数)
//size:字体大小
//mode:
//[7]:0,不填充;1,填充0.
//[6:1]:保留
//[0]:0,非叠加显示;1,叠加显示.
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)
{  
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/LCD_Pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				if(mode&0X80)LCD_ShowChar(x+(size/2)*t,y,'0',size,mode&0X01);  
				else LCD_ShowChar(x+(size/2)*t,y,' ',size,mode&0X01);  
 				continue;
			}else enshow=1; 
		 	 
		}
	 	LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode&0X01); 
	}
} 
//显示字符串
//x,y:起点坐标
//width,height:区域大小  
//size:字体大小
//*p:字符串起始地址		  
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)
{         
	u8 x0=x;
	width+=x;
	height+=y;
    while((*p==0x0A) || ((*p<='~')&&(*p>=' ')))//判断是不是非法字符!
    {       
		if (*p==0x0A) { //换行符
			x = x0;
			y += size;
			p++;
			continue;
		}
        if(x>=width){x=x0;y+=size;}
        if(y>=height)break;//退出
        LCD_ShowChar(x,y,*p,size,0);
        x+=size/2;
        p++;
    }  
}

//画线
//x1,y1:起点坐标
//x2,y2:终点坐标  
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
	u16 t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 
	delta_x=x2-x1; //计算坐标增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //设置单步方向 
	else if(delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平线 
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//画线输出 
	{  
		LCD_DrawPoint(uRow,uCol);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
}

//画矩形	  
//(x1,y1),(x2,y2):矩形的对角坐标
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
	LCD_DrawLine(x1,y1,x2,y1);
	LCD_DrawLine(x1,y1,x1,y2);
	LCD_DrawLine(x1,y2,x2,y2);
	LCD_DrawLine(x2,y1,x2,y2);
}

//在指定位置画一个指定大小的圆
//(x,y):中心点
//r    :半径
void Draw_Circle(u16 x0,u16 y0,u8 r)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //判断下个点位置的标志
	while(a<=b)
	{
		LCD_DrawPoint(x0+a,y0-b);             //5
 		LCD_DrawPoint(x0+b,y0-a);             //0           
		LCD_DrawPoint(x0+b,y0+a);             //4               
		LCD_DrawPoint(x0+a,y0+b);             //6 
		LCD_DrawPoint(x0-a,y0+b);             //1       
 		LCD_DrawPoint(x0-b,y0+a);             
		LCD_DrawPoint(x0-a,y0-b);             //2             
  		LCD_DrawPoint(x0-b,y0-a);             //7     	         
		a++;
		//使用Bresenham算法画圆     
		if(di<0)di +=4*a+6;	  
		else
		{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
}

void LCD_DrawBackground(void)
{
	LCD_Fill(0,0,159,79, BLACK);//清屏(屏幕为黑色)
	LCD_DrawRectangle(0,0,159,79);
    LCD_DrawLine(0,19,159,19); //第一条横线
    LCD_DrawLine(99,19,99,79); //第一条竖线
    LCD_DrawLine(129,19,129,79); //第二条竖线
    LCD_DrawLine(99,49,159,49);  //第二条横线

    // LCD_ShowString(2,19,99,19,12,"id dlc data");  //第三条横线
    LCD_ShowString(2,2,50,20,12,"RX");
    LCD_ShowString(50,2,50,20,12,"TX");
    LCD_ShowString(100,2,50,20,12,"ERR");
}

#if 1

void LCD_SetCanStatus(uint8_t status)
{
    g_canStatus = status;
}

void LCD_PutFrame(struct gs_host_frame *frame, uint8_t frame_type)
{
    if (frame == NULL) return;
    g_frameType = frame_type;
    if (g_haveFrame == 1) return;
    memcpy((void *)&g_printFrame, (void *)frame, sizeof(struct gs_host_frame));
    g_frameShowCnt = 0;
    g_haveFrame = 1;
}

uint8_t *GetFontData(char c, uint8_t size) {
    // 根据字符和大小获取字模数据
    // 这里需要你根据你的字库实现此函数
    // 返回字模数据指针
    uint8_t *temp = NULL;
    u8 csize=(size/8+((size%8)?1:0))*(size/2);		//得到字体一个字符对应点阵集所占的字节数	
    u8 num = c - ' ';//得到偏移后的值（ASCII字库是从空格开始取模，所以-' '就是对应字符的字库）
    if(size==12)temp = &asc2_1206[num]; 	 	//调用1206字体
    else if(size==16)temp = &asc2_1608[num];	//调用1608字体
    else if(size==24)temp = &asc2_2412[num];	//调用2412字体
    return temp;
}

// 绘制一个字符到帧缓冲区
void LCD_DrawCharToFrame(uint16_t x, uint16_t y, char c, uint8_t size, uint16_t *frame, uint16_t frameWidth) {
    // 获取字符点阵数据（需要你提供12x6字库）
    const uint8_t *fontData = GetFontData(c, size); // 实现此函数获取字模
    uint16_t color = POINT_COLOR;
    uint8_t mode = 0;
    uint16_t y0=y;
		uint8_t temp = 0;
    u8 num = c - ' ';//得到偏移后的值（ASCII字库是从空格开始取模，所以-' '就是对应字符的字库）
    if (!fontData) return; // 如果字模数据为空，则返回
    for (int i = 0; i < 12; i++) { // 12行
				if(size==12)temp = asc2_1206[num][i]; 	 	//调用1206字体
				else if(size==16)temp = asc2_1608[num][i];	//调用1608字体
				else if(size==24)temp = asc2_2412[num][i];	//调用2412字体
        uint8_t lineData = temp;
        for (int j = 0; j < 8; j++) {
            if(lineData&0x80) {
                color = POINT_COLOR;
            } else if(mode==0) {
                color = BACK_COLOR;
            }
            frame[(y * frameWidth) + x] = color; // 设置像素颜色
            lineData<<=1;
            y++;
            if(y>=lcddev.height)return;		//超区域了
            if((y-y0)==size)
            {
                y=y0;
                x++;
                if(x>=lcddev.width)return;	//超区域了
                break;
            }
        }
    }
}

// 绘制字符串到帧缓冲区
void LCD_DrawStringToFrame(char *str, uint8_t size, uint16_t *frame, uint16_t frameWidth) {
    uint16_t currentX = 0;
    uint16_t currentY = 0;
    uint16_t charSpace = 0;
    uint16_t lineSpace = 0;

    while (*str) {
        if (*str == '\n') { // 处理换行
            currentX = 0;
            currentY += size + lineSpace; // 行间距
        } else {
            LCD_DrawCharToFrame(currentX, currentY, *str, size, frame, frameWidth);
            currentX += 6 + charSpace; // 字符宽度 + 间距
        }
        str++;
    }
}

void LCD_UpdateFrameDMA(TaskInfo *task, uint8_t *frameData, uint32_t frameSize) {
    // 设置LCD写入区域
    LCD_Set_Window(task->draw_start_x, task->draw_start_y, task->draw_width, task->draw_height);
    uint32_t dataSize = task->draw_width * task->draw_height * 2;
    if (dataSize > frameSize) {
        dataSize = frameSize;
    }
    TFT_RS(1);
    // 启动DMA传输
    HAL_SPI_Transmit_DMA(&hspi1, frameData, dataSize);
}

/**
 * @brief 设置LCD数据直接传输方向
 * @param dir 数据传输方向，0表示下载，非0表示上传
 * @note 该函数通过DMA方式传输图像数据到LCD显示屏
 */
uint8_t LCD_SetDataDirect(TaskInfo *task)
{
    static uint8_t g_lastFrameType = CAN_NOACT;
    if (task==NULL) return 0;
    if (g_frameType == CAN_NOACT || g_frameType == g_lastFrameType) return 0;
    g_lastFrameType = g_frameType;
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 设置显示窗口区域
    LCD_Set_Window(task->draw_start_x, task->draw_start_y, task->draw_width, task->draw_height);
    // 设置LCD为数据模式
    TFT_RS(1);
    u8 *data = NULL;
    if(g_frameType == 0) {  // download data
            data = (u8*)downloadimage_28x28;
    }
    else if (g_frameType == 1){  // upload data
            data = (u8*)uploadimage_28x28;
    } else {
            data = (u8*)noaction_image_28x28;
    }
    g_frameType = CAN_NOACT;
    HAL_SPI_Transmit_DMA(&hspi1, data, 28*28*2);
    // while(HAL_DMA_GetState(&hdma_spi1_tx) == HAL_DMA_STATE_BUSY);
    return 0;
}

uint8_t LCD_SetConnectStatus(TaskInfo *task)
{
    if (task==NULL) return 0;
    if (g_canStatus == CAN_NOCHANGE) return 0;
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 设置显示窗口区域
    LCD_Set_Window(task->draw_start_x, task->draw_start_y, task->draw_width, task->draw_height);
    // 设置LCD为数据模式
    TFT_RS(1);
    u8 *data = NULL;
    if(g_canStatus == 0) {  // nolink
            data = (u8*)nolink_image_28x28;
    }
    else {  // link
            data = (u8*)link_image_28x28;
    }
    HAL_SPI_Transmit_DMA(&hspi1, data, 28*28*2);
    // while(HAL_DMA_GetState(&hdma_spi1_tx) == HAL_DMA_STATE_BUSY);
    g_canStatus = CAN_NOCHANGE;
    return 0;
}

uint8_t LCD_ShowFrameID_DLC(TaskInfo *task) 
{
    static uint32_t old_can_id = 0;
    static uint8_t old_can_dlc = 0;
	if (task==NULL) return 0;
	if (g_haveFrame == 0) return 0;
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    if (g_frameShowCnt >= 2) {
        g_frameShowCnt = 0;
        g_haveFrame = 0;
    }
    // 1. 获取帧数据
    struct gs_host_frame *frame = &g_printFrame;
    if ((frame->can_id == old_can_id) && (frame->can_dlc == old_can_dlc)) {
        g_frameShowCnt++;
        return 0;
    }
    old_can_id = frame->can_id;
    old_can_dlc = frame->can_dlc;
    // 2. 格式化字符串
    char str[30] = {0};
    sprintf(str, "ID:%04d DLC:%01d", frame->can_id, frame->can_dlc);
    g_frameShowCnt++;
    // 3. 将字符串绘制到帧缓冲区（修改后的函数）
    LCD_DrawStringToFrame(str, 12, lineFrameBuffer, task->draw_width);
    return 1;
}

uint8_t LCD_ShowFrameHalfData(TaskInfo *task) 
{
	if (task==NULL) return 0;
	if (g_haveFrame == 0) return 0;
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 1. 获取帧数据
    struct gs_host_frame *frame = &g_printFrame;
    // 2. 格式化字符串
    char str[30] = {0};
    sprintf(str, "Data: %02X %02X %02X", frame->data[0], frame->data[1], frame->data[2]);
    if (g_frameShowCnt >= 2) {
        g_frameShowCnt = 0;
        g_haveFrame = 0;
    }
    g_frameShowCnt++;
    // 3. 将字符串绘制到帧缓冲区（修改后的函数）
    LCD_DrawStringToFrame(str, 12, lineFrameBuffer, task->draw_width);
    return 1;
}

uint8_t LCD_ShowFrameRemainData(TaskInfo *task) 
{
	if (task==NULL) return 0;
	if (g_haveFrame == 0) return 0;
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 1. 获取帧数据
    struct gs_host_frame *frame = &g_printFrame;
    // 2. 格式化字符串
    char str[30] = {0};
    sprintf(str, "%02X %02X %02X %02X %02X", frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]);
    if (g_frameShowCnt >= 2) {
        g_frameShowCnt = 0;
        g_haveFrame = 0;
    }
    g_frameShowCnt++;
    // 3. 将字符串绘制到帧缓冲区（修改后的函数）
    LCD_DrawStringToFrame(str, 12, lineFrameBuffer, task->draw_width);
    return 1;
}

extern void Can_GetFrameTxRxInfo(uint32_t *frame_rxcnt, uint32_t *frame_txcnt);
extern void Can_GetFrameErrInfo(uint32_t *frame_err);
uint8_t LCD_ShowRxInfo(TaskInfo *task)
{
    if (task==NULL) return 0;
    // 1. 获取串口数据
    uint32_t rx = 0;
    uint32_t tx = 0; 
    static uint32_t last_rx = 0xffff;
    Can_GetFrameTxRxInfo(&rx, &tx);
    if(rx == last_rx) {
        return 0;
    }
    last_rx = rx;
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 2. 格式化字符串
    char frameBuf[15] = {0};
   sprintf(frameBuf, "RX:%08d", rx, tx);
    // 3. 将字符串绘制到帧缓冲区（修改后的函数）
    LCD_DrawStringToFrame(frameBuf, 12, lineFrameBuffer, task->draw_width);
    return 1;
}

uint8_t LCD_ShowTxInfo(TaskInfo *task)
{
    if (task==NULL) return 0;
    // 1. 获取串口数据
    uint32_t rx = 0;
    uint32_t tx = 0; 
    static uint32_t	last_tx = 0xffff;
    Can_GetFrameTxRxInfo(&rx, &tx);
    if(tx == last_tx) {
        return 0;
    }
    last_tx = tx;

    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 2. 格式化字符串
    char frameBuf[15] = {0};
   sprintf(frameBuf, "TX:%08d", tx);
    // 3. 将字符串绘制到帧缓冲区（修改后的函数）
    LCD_DrawStringToFrame(frameBuf, 12, lineFrameBuffer, task->draw_width);
    return 1;
}

uint8_t LCD_ShowErrInfo(TaskInfo *task)
{
    static uint32_t last_time = 0xffff;
    if (task==NULL) return 0;
    // 1. 获取串口数据
    uint32_t err = 0;
    static uint32_t last_err = 0xffff;
    Can_GetFrameErrInfo(&err);
    if((err == last_err) || ((HAL_GetTick() - last_time) < 1000)) {
        return 0;
    }
    last_err = err;
    last_time = HAL_GetTick();
    memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色
    // 2. 格式化字符串
    char frameBuf[30] = {0};
   sprintf(frameBuf, "ERR:%#x", err);
    // 3. 将字符串绘制到帧缓冲区（修改后的函数）
    LCD_DrawStringToFrame(frameBuf, 12, lineFrameBuffer, task->draw_width);
    return 1;
}

#define CAN_TASK_SIZE 8
TaskInfo g_taskList[CAN_TASK_SIZE] = {
    {DRAW_CAN_INFO,     2,   2,  76,  12, LCD_ShowRxInfo},
    {DRAW_CAN_INFO,     80,  2,  76,  12, LCD_ShowTxInfo},
    {DRAW_CAN_INFO,     2,   21, 90,  12, LCD_ShowErrInfo},
    {DRAW_CAN_FRAME,    2,   35, 90,  12, LCD_ShowFrameID_DLC},
    {DRAW_CAN_FRAME,    2,   49, 90,  12, LCD_ShowFrameHalfData},
    {DRAW_CAN_FRAME,    2,   65, 90,  12, LCD_ShowFrameRemainData},
    {DRAW_CAN_DATA_DIR, 101, 21, 28,  28, LCD_SetDataDirect},
    {DRAW_CAN_CONNECT,  131, 21, 28,  28, LCD_SetConnectStatus},
    {NONE,              2,   21, 99,  12, NULL},
};

// 在你的主循环中调用此任务
void LCD_Task(void)
{
    static uint8_t task_cnt = 0;
    uint8_t ret = 0;
    if (HAL_DMA_GetState(&hdma_spi1_tx) == HAL_DMA_STATE_BUSY) {
        return;
    }
    // 1. 清空帧缓冲区（填充背景色）
    // memset(lineFrameBuffer, 0x00, sizeof(lineFrameBuffer)); // 0x00为背景色，0xFF为前景色

    // 2. 根据任务计数器选择任务
    TaskInfo *task = &g_taskList[task_cnt];

    // 3. 执行任务函数并获取返回值
    if (task->task_func) {
        ret = task->task_func(task);
    }
    task_cnt++;
    if (task_cnt >= CAN_TASK_SIZE) {
        task_cnt = 0;
    }

    // 4. 通过DMA传输整个帧缓冲区到LCD
    if(ret) {
        LCD_UpdateFrameDMA(task, (uint8_t *)lineFrameBuffer, sizeof(lineFrameBuffer));
    }
}
#endif
